package com.codeoss.framework.webide.service.impl;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.codeoss.framework.data.metadata.Table;
import com.codeoss.framework.data.store.ITableStore;
import com.codeoss.framework.db.service.IDDLService;
import com.codeoss.framework.db.service.impl.IDDLServiceStore;
import com.codeoss.framework.util.DBUtil;
import com.codeoss.framework.util.ValueNamePair;
import com.codeoss.framework.webide.request.ModelWizardDialogRequest;
import com.codeoss.framework.webide.response.ModelWizardDialogResponse;
import com.codeoss.framework.webide.service.IModelWizardDialogService;
import com.codeoss.module.ir.model.IrModel;
import com.codeoss.module.ir.service.IIrDictService;
import com.codeoss.module.ir.service.IIrModelService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

@Service
public class ModelWizardDialogService implements IModelWizardDialogService {
	@Autowired
	private ObjectMapper objectMapper;
	@Autowired
	private DataSource dataSource;
	@Autowired
	private DBUtil dbUtil;
	@Autowired
    private IIrModelService irModelService;
	@Autowired
    private IIrDictService irDictService;
	@Autowired
	private IDDLServiceStore ddlServiceStore;
	@Autowired
	private ITableStore tableStore;
	private static final List<String> baseColumnList=new ArrayList<String>();
	private static final List<String> treeColumnList=new ArrayList<String>();
	static {
		baseColumnList.add("id");
		baseColumnList.add("res_org_id");
		baseColumnList.add("active");
		baseColumnList.add("create_by");
		baseColumnList.add("create_date");
		baseColumnList.add("update_by");
		baseColumnList.add("update_date");
		baseColumnList.add("version");
	}
	static {
		treeColumnList.add("name");
		treeColumnList.add("parent_id");
		treeColumnList.add("path");
		treeColumnList.add("seq_no");
	}
	@Override
	@Transactional
	public ModelWizardDialogResponse onFinish(ModelWizardDialogRequest request) {
		// TODO Auto-generated method stub
		ModelWizardDialogResponse modelWizardDialogResponse=new ModelWizardDialogResponse();
		ObjectNode objectNode=null;
		try {
			objectNode=(ObjectNode)objectMapper.readTree(request.getJson());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		}
		
		String moduleType=objectNode.get("moduleTypeSelectPage").get("moduleType").asText();
		
		String modelType=objectNode.get("modelTypeSelectPage").get("modelType").asText();
		
		String tableName=objectNode.get("modelBaseInfoPage").get("tableName").asText();
		String name=objectNode.get("modelBaseInfoPage").get("name").asText();
		String description=objectNode.get("modelBaseInfoPage").get("description").asText();
		
		IrModel irModel=irModelService.getIrModelByTableName(tableName);
		if(irModel!=null) {
			throw new RuntimeException("已存在此表纪录");
		}
		irModel=new IrModel();
		irModel.setModuleType(moduleType);
		irModel.setModelType(modelType);
		irModel.setTableName(tableName);
		irModel.setName(name);
		irModel.setDescription(description);
		
		if("table".equals(modelType)) {
			fillTableModel(irModel,objectNode,null);
		}else if("para".equals(modelType)) {
			String jsonContent=createJsonContentFromTable(irModel, "", false, "",null,false);
			irModel.setJsonContent(jsonContent);
		}else if("view".equals(modelType)) {
			String sql=objectNode.get("sqlPage").get("sql").asText();
			fillTableModel(irModel,objectNode,sql);
		}
		irModelService.insert(irModel);
		
		if("view".equals(modelType)) {
			Table table=tableStore.get(irModel.getTableName());
			String jsonContent=createJsonContentFromTable(irModel,table.getPackageName(), false, table.getAccessType(),table.getSql(),true);
			irModel.setJsonContent(jsonContent);
			irModelService.update(irModel);
		}
		modelWizardDialogResponse.setItem(new ValueNamePair(irModel.getName(),irModel.getTableName()));
		return modelWizardDialogResponse;
	}
	
	public void fillTableModel(IrModel irModel,ObjectNode objectNode,String sql) {
		String packageName=objectNode.get("modelExtraInfoPage").get("packageName").asText();
		boolean treeTable=objectNode.get("modelExtraInfoPage").get("treeTable").asBoolean();
		String accessType=objectNode.get("modelExtraInfoPage").get("accessType").asText();
		String jsonContent=createJsonContentFromTable(irModel, packageName, treeTable, accessType,sql,false);
		irModel.setJsonContent(jsonContent);
	}
	
	private String createJsonContentFromTable(IrModel irModel,String packageName,boolean treeTable,String accessType,String sql,boolean createView) {
		Map<String,Object> tableMap=new HashMap<String,Object>();
		tableMap.put("tableName", irModel.getTableName());
		tableMap.put("name",irModel.getName());
		tableMap.put("packageName",packageName);
		String modelType=irModel.getModelType();
		if("table".equals(modelType)) {
			if(!treeTable) {
				tableMap.put("extendsTable", "base_table");
			}else {
				tableMap.put("extendsTable", "base_tree");
			}
		}
		tableMap.put("abstractTable",false);
		if("table".equals(modelType)) {
			tableMap.put("view",false);
			tableMap.put("auto",true);
		}else if("para".equals(modelType)) {
			tableMap.put("view",false);
			tableMap.put("auto",false);
		}else if("view".equals(modelType)) {
			tableMap.put("view",true);
			tableMap.put("auto",true);
		}
		tableMap.put("accessType", accessType);
		if("view".equals(modelType)) {
			tableMap.put("sql",sql);
		}
		if("view".equals(modelType) && irModel.getId()!=null) {
			Table table=tableStore.get(irModel.getTableName());
			tableStore.remove(irModel.getTableName());
			IDDLService ddlService=ddlServiceStore.getDDLService();
			Connection conn=null;
			try {
				conn=dataSource.getConnection();
				ddlService.createView(conn, table);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				throw new RuntimeException(e);
			}finally {
				dbUtil.closeConnection(conn);
			}
		}
		List<Map<String,Object>> columnMapList=new ArrayList<Map<String,Object>>();
		tableMap.put("columnList", columnMapList);
		
		fillColumnMapList(columnMapList,irModel,treeTable);
		ObjectMapper objectMapper=new ObjectMapper();
		String jsonContent=null;
		try {
			jsonContent = objectMapper.writeValueAsString(tableMap);
		} catch (JsonProcessingException e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		}
		return jsonContent;
	}
	
	private void fillColumnMapList(List<Map<String,Object>> columnMapList,IrModel irModel,boolean treeTable) {
		Connection conn=null;
		ResultSet rs=null;
		String modelType=irModel.getModelType();
		try {
			conn=dataSource.getConnection();
			DatabaseMetaData md = conn.getMetaData();
			rs = md.getColumns(null, null, irModel.getTableName(), null);
			while(rs.next()) {
				String columnName = rs.getString ("COLUMN_NAME");
				if("table".equals(modelType)) {
					if(baseColumnList.contains(columnName)) {
						continue;
					}
					if(treeTable) {
						if(treeColumnList.contains(columnName)) {
							continue;
						}
					}
					
				}
				Map<String,Object> columnMap=new HashMap<String,Object>();
				columnMapList.add(columnMap);
				
				columnMap.put("columnName", columnName);
				columnMap.put("name", columnName);
				
				String nullable = rs.getString ("IS_NULLABLE");
				int size = rs.getInt ("COLUMN_SIZE");
				int digits = rs.getInt ("DECIMAL_DIGITS");
				
				String sDataType="long";
				int dataType = rs.getInt ("DATA_TYPE");
				if(columnName.endsWith("_id")) {
					sDataType="long";
				}else if(dataType==Types.INTEGER) {
					sDataType="integer";
				}else if(dataType==Types.NUMERIC ||dataType==Types.DECIMAL) {
					sDataType="bigdecimal";
					
					columnMap.put("length", size);
					columnMap.put("precision", digits);
					
				}else if(dataType==Types.CHAR) {
					if(size==1) {
						sDataType="boolean";
					}else {
						sDataType="string";
						columnMap.put("length", size);
					}
				}else if(dataType==Types.VARCHAR) {
					sDataType="string";
					columnMap.put("length", size);
				}else if(dataType==Types.TIMESTAMP) {
					sDataType="datetime";
				}else if(dataType==Types.DATE) {
					sDataType="date";
				}else if(dataType==Types.TIME) {
					sDataType="time";
				}
				columnMap.put("dataType",sDataType);
				columnMap.put("notNull","NO".equals (nullable));
			}
			
		
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		}finally {
			dbUtil.closeResultSet(rs);
			dbUtil.closeConnection(conn);
		}
	}

	@Override
	public ModelWizardDialogResponse initModuleTypeSelectPage() {
		// TODO Auto-generated method stub
		ModelWizardDialogResponse modelWizardDialogResponse=new ModelWizardDialogResponse();
		List<ValueNamePair> moduleTypeList=irDictService.getPairListByCode("moduleType");
		modelWizardDialogResponse.setModuleTypeList(moduleTypeList);
		return modelWizardDialogResponse;
	}

}
